package com.gitee.wsl.android.ui.ext

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.createScaledBitmap
import android.graphics.BitmapFactory.decodeResource
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.PointF
import android.graphics.RectF
import android.util.TypedValue
import android.util.TypedValue.COMPLEX_UNIT_DIP
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_CANCEL
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_MASK
import android.view.MotionEvent.ACTION_MOVE
import android.view.MotionEvent.ACTION_POINTER_DOWN
import android.view.MotionEvent.ACTION_UP
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.gitee.wsl.android.ui.R
import com.gitee.wsl.ext.coroutines.LifecycleExt.coroutineDelay
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlin.math.abs
import kotlin.math.atan2
import kotlin.math.pow
import kotlin.math.sqrt


/**
 * 拦截滑动辅助器（用于[ViewGroup.onInterceptTouchEvent]）
 * <br></br>使用方法：<br></br>
 * public boolean onInterceptTouchEvent(MotionEvent ev)&nbsp;{<br></br>
 * &nbsp;&nbsp;&nbsp;&nbsp;boolean result = super.onInterceptTouchEvent(ev);<br></br>
 * &nbsp;&nbsp;&nbsp;&nbsp;boolean ext = interceptTouchHelper.onInterceptTouchEvent(ev);<br></br>
 * &nbsp;&nbsp;&nbsp;&nbsp;return result && ext;<br></br>
 * }
 */
class InterceptTouchHelper @JvmOverloads constructor(
    private val parent: ViewGroup,
    private val gestureHelper: GestureHelper = GestureHelper.createDefault(parent.context)
) {

    /**
     * 判定是否拦截触摸事件
     *
     * @param event 触摸事件
     * @return true，拦截
     */
    fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        gestureHelper.onTouchEvent(event)
        when (gestureHelper.gesture) {
            GestureHelper.GESTURE_LEFT ->
                return (!canChildrenScrollHorizontally(event, 1) && canParentScrollHorizontally(parent, 1))
            GestureHelper.GESTURE_RIGHT ->
                return (!canChildrenScrollHorizontally(event, -1) && canParentScrollHorizontally(parent, -1))
            GestureHelper.GESTURE_UP ->
                return (!canChildrenScrollVertically(event, 1) && canParentScrollVertically(parent, 1))
            GestureHelper.GESTURE_DOWN ->
                return (!canChildrenScrollVertically(event, -1) && canParentScrollVertically(parent, -1))
        }
        return false
    }

    /**
     * 判断子视图是否可以垂直滑动
     *
     * @param event     滑动事件
     * @param direction 方向：负数表示ScrollY值变小的方向；整数表示ScrollY值变大的方向
     * @return true，子View可以滑动
     */
    protected fun canChildrenScrollVertically(event: MotionEvent, direction: Int): Boolean {
        for (i in 0 until parent.childCount) {
            val index = parent.childCount - 1 - i
            val child: View = parent.getChildAt(index)
            if (child.visibility == View.VISIBLE && child.isEnabled) {
                val x = event.x
                val y = event.y
                if (x >= child.getLeft() && x <= child.getRight() && y >= child.getTop() && y <= child.getBottom()) {
                    if (canChildScrollVertically(child, direction)) {
                        return true
                    }
                }
            }
        }
        return false
    }

    /**
     * 判断子View是否可以垂直滑动
     *
     * @param child     子View
     * @param direction 方向：负数表示ScrollY值变小的方向；整数表示ScrollY值变大的方向
     * @return true，可以滑动
     */
    protected fun canChildScrollVertically(child: View, direction: Int): Boolean {
        return child.canScrollVertically(direction)
    }

    /**
     * 判断子视图是否可以水平滑动
     *
     * @param event     滑动事件
     * @param direction 方向：负数表示ScrollX值变小的方向；整数表示ScrollX值变大的方向
     * @return true，子View可以滑动
     */
    protected fun canChildrenScrollHorizontally(event: MotionEvent, direction: Int): Boolean {
        for (i in 0 until parent.childCount) {
            val index = parent.childCount - 1 - i
            val child: View = parent.getChildAt(index)
            if (child.visibility == View.VISIBLE && child.isEnabled) {
                val x = event.x
                val y = event.y
                if (x >= child.left && x <= child.right && y >= child.top && y <= child.bottom) {
                    if (canChildScrollHorizontally(child, direction)) {
                        return true
                    }
                }
            }
        }
        return false
    }

    /**
     * 判断子View是否可以水平滑动
     *
     * @param child     子View
     * @param direction 方向：负数表示ScrollX值变小的方向；整数表示ScrollX值变大的方向
     * @return true，可以滑动
     */
    protected fun canChildScrollHorizontally(child: View, direction: Int): Boolean {
        return child.canScrollHorizontally(direction)
    }

    /**
     * 判断父视图是否可以水平滑动
     *
     * @param parent    父视图
     * @param direction 方向
     * @return true，可以水平滑动
     */
    protected fun canParentScrollHorizontally(parent: ViewGroup, direction: Int): Boolean {
        return parent.canScrollHorizontally(direction)
    }

    /**
     * 判断父视图是否可以垂直滑动
     *
     * @param parent    父视图
     * @param direction 方向
     * @return true，可以水平滑动
     */
    protected fun canParentScrollVertically(parent: ViewGroup, direction: Int): Boolean {
        return parent.canScrollVertically(direction)
    }
}

/**
 * 手势辅助器
 */
class GestureHelper(pointSize: Float, longClickTime: Int, xyScale: Float) {

    // 点的大小
    private val pointSize : Float
    // 长按判定时间
    private val longClickTime : Int
    private val xyScale: Float

    /**
     * 获取手势
     *
     * @return 手势
     */
    var gesture = GESTURE_NONE // 手势
        private set
    private var downTime: Long = 0
    private var downX = 0f
    private var downY = 0f
    private var preX = 0f
    private var preY = 0f

    /**
     * 创建一个手势帮助器
     *
     * @param pointSize     点的大小，超出此大小的滑动手势会被判定为非点击手势
     * @param longClickTime 长按点击时间，超过或等于此时间的按住手势算长按点击事件
     * @param xyScale       X轴与Y轴比例，影响方向手势的判定，默认是1；
     * 越小，手势判定越偏重于水平方向；
     * 越大，手势判定偏重于垂直方向；
     * 1，不偏重任何方向；
     * 如果是专注于水平方向，可以将此值设置小于1的数，
     * 如果是专注于垂直方向，可以将此值设置大于1的数；
     * 如果是垂直与水平同等重要，将此值设置成1
     */
    init {
        require(pointSize > 0) { "Illegal:pointSize <= 0" }
        require(longClickTime > 0) { "Illegal:longClickTime <= 0" }
        require(xyScale != 0f) { "Illegal:xyScale equals 0" }
        this.pointSize = pointSize
        this.longClickTime = longClickTime
        this.xyScale = xyScale
    }

    /**
     * 触发触摸滑动事件
     *
     * @param event 事件
     */
    fun onTouchEvent(event: MotionEvent) {
//        System.out.println("onTouchEvent:action=" + event.getAction());
        when (event.action) {
            MotionEvent.ACTION_DOWN -> touchDown(event)
            MotionEvent.ACTION_MOVE -> touchMove(event)
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> touchFinish(event)
        }
        //        System.out.println("onTouchEvent:" + gesture);
    }

    /**
     * 判定是否为水平滑动手势
     *
     * @return true，水平滑动手势
     */
    val isHorizontalGesture: Boolean
        get() = gesture == GESTURE_LEFT || gesture == GESTURE_RIGHT

    /**
     * 判定是否为垂直滑动手势
     *
     * @return true，垂直滑动手势
     */
    val isVerticalGesture: Boolean
        get() = gesture == GESTURE_UP || gesture == GESTURE_DOWN

    private fun touchDown(event: MotionEvent) {
        downTime = System.currentTimeMillis()
        preX = event.rawX
        downX = preX
        preY = event.rawY
        downY = preY
        gesture = GESTURE_PRESSED
    }

    private fun touchMove(event: MotionEvent) {
        val rangeX = event.rawX - downX
        val rangeY = event.rawY - downY
        //        System.out.println(String.format("touchMove:rangeX=%f,rangeY=%f,pointSize=%f",
//                rangeX, rangeY, pointSize));
        if (gesture == GESTURE_NONE || gesture == GESTURE_PRESSED) { // 未确定手势或正在长按
            gesture = if (Math.abs(rangeX) > pointSize || Math.abs(rangeY) > pointSize) {
                // 超出点的范围，不算点击、按住手势，应该是滑动手势
                val ox = event.rawX - preX
                val oy = event.rawY - preY
                if (Math.abs(ox) > xyScale * Math.abs(oy)) {
                    // 水平方向滑动
                    if (ox < 0) {
                        GESTURE_LEFT
                    } else {
                        GESTURE_RIGHT
                    }
                } else {
                    // 垂直方向滑动
                    if (oy < 0) {
                        GESTURE_UP
                    } else {
                        GESTURE_DOWN
                    }
                }
            } else {
                GESTURE_PRESSED // 按住手势
            }
        }
        if (gesture == GESTURE_PRESSED) { // 按住中
            if (System.currentTimeMillis() - downTime >= longClickTime) { // 按住超过长按时间，算长按时间
                gesture = GESTURE_LONG_CLICK
            }
        }
        preX = event.rawX
        preY = event.rawY
    }

    private fun touchFinish(event: MotionEvent) {
        if (gesture == GESTURE_PRESSED) { // 按住到释放，应该算点击手势
            gesture =
                if (System.currentTimeMillis() - downTime >= longClickTime) { // 按住超过长按时间，算长按时间
                    GESTURE_LONG_CLICK
                } else {
                    GESTURE_CLICK
                }
        }
    }

    companion object {
        /**
         * 无手势，还不能确定手势
         */
        const val GESTURE_NONE = 0

        /**
         * 手势：按住
         */
        const val GESTURE_PRESSED = 1

        /**
         * 手势：点击
         */
        const val GESTURE_CLICK = 2

        /**
         * 手势：长按
         */
        const val GESTURE_LONG_CLICK = 3

        /**
         * 手势：左滑
         */
        const val GESTURE_LEFT = 4

        /**
         * 手势：上滑
         */
        const val GESTURE_UP = 5

        /**
         * 手势：右滑
         */
        const val GESTURE_RIGHT = 6

        /**
         * 手势：下滑
         */
        const val GESTURE_DOWN = 7

        /**
         * 默认的点大小，单位：dip
         */
        const val DEFAULT_FONT_SIZE_DP = 5f

        /**
         * 默认的长按时间
         */
        const val DEFAULT_LONG_CLICK_TIME = 800

        /**
         * 创建默认的手势辅助器
         *
         * @param context 上下文对象
         * @return 手势器
         */
        fun createDefault(context: Context): GestureHelper {
            val pointSize = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                DEFAULT_FONT_SIZE_DP, context.resources.displayMetrics
            )
            return GestureHelper(pointSize, DEFAULT_LONG_CLICK_TIME, 1f)
        }
    }
}


class ViewControlHelper(val view: View,var matrixGet:(()-> Matrix)? =null):View.OnTouchListener{

    private val context = view.context

    // 控件宽度
    private var mWidth = 0

    // 控件高度
    private var mHeight = 0

    // 第一次绘制
    private var mFirstDraw = true

    // 是否显示控制框
    private var mShowFrame = false

    // 当前Image矩阵
    private var mImgMatrix = Matrix()

    // 画笔
    private lateinit var mPaint: Paint

    // 触摸模式
    private var touchMode: TouchMode? = null

    // 第二根手指是否按下
    private var mIsPointerDown = false

    // 按下点x坐标
    private var mDownX = 0f

    // 按下点y坐标
    private var mDownY = 0f

    // 上一次的触摸点x坐标
    private var mLastX = 0f

    // 上一次的触摸点y坐标
    private var mLastY = 0f

    // 旋转角度
    private var mDegree: Float = 0.0f

    // 旋转图标
    private lateinit var mRotateIcon: Bitmap

    // 图片控制框颜色
    private var mFrameColor = Color.parseColor("#1677FF")

    // 连接线宽度
    private var mLineWidth = dp2px(context, 2f)

    // 缩放控制点半径
    var mScaleDotRadius = dp2px(context, 5f)

    // 旋转控制点半径
    var mRotateDotRadius = dp2px(context, 12f)

    // 按下监听
    private var mDownClickListener: ((view: View, pointF: PointF) -> Unit)? = null

    // 长按监听
    private var mLongClickListener: ((view: View, pointF: PointF) -> Unit)? = null

    // 移动监听
    private var mMoveListener: ((view: View, pointF: PointF) -> Unit)? = null

    // 长按监听计时任务
    private var mLongClickJob: Job? = null


    // Matrix模式
    var scaleType = ImageView.ScaleType.MATRIX

    init {
        init()
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun init() {
        mPaint = Paint()
        mPaint.isAntiAlias = true
        mPaint.strokeWidth = mLineWidth
        mPaint.color = mFrameColor
        mPaint.style = Paint.Style.FILL

        // 旋转图标
        val rotateIcon = decodeResource(context.resources, R.drawable.ic_play)
        val rotateIconWidth = (mRotateDotRadius * 1.6f).toInt()
        mRotateIcon = createScaledBitmap(rotateIcon, rotateIconWidth, rotateIconWidth, true)

        view.setOnTouchListener(this)
    }

    fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        //super.onSizeChanged(w, h, oldw, oldh)
        this.mWidth = w
        this.mHeight = h
    }

     fun draw(canvas: Canvas) {

        val imgRect = getImageRectF()
        // 左上角x坐标
        val left = imgRect.left
        // 左上角y坐标
        val top = imgRect.top
        // 右下角x坐标
        val right = imgRect.right
        // 右下角y坐标
        val bottom = imgRect.bottom

        // 图片移动到控件中心
        if (mFirstDraw) {
            mFirstDraw = false
            val centerX = (mWidth / 2).toFloat()
            val centerY = (mHeight / 2).toFloat()
            val imageWidth = right - left
            val imageHeight = bottom - top
            mImgMatrix.postTranslate(centerX - imageWidth / 2, centerY - imageHeight / 2)
            // 如果图片较大，缩放0.5倍
            if (imageWidth > mWidth || imageHeight > mHeight) {
                mImgMatrix.postScale(0.5f, 0.5f, centerX, centerY)
            }
        }

        // 不绘制控制框
        if (!mShowFrame) {
            return
        }

        // 上边框
        canvas.drawLine(left, top, right, top, mPaint)
        // 下边框
        canvas.drawLine(left, bottom, right, bottom, mPaint)
        // 左边框
        canvas.drawLine(left, top, left, bottom, mPaint)
        // 右边框
        canvas.drawLine(right, top, right, bottom, mPaint)

        // 左上角控制点，等比缩放
        canvas.drawCircle(left, top, mScaleDotRadius, mPaint)
        // 右上角控制点，等比缩放
        canvas.drawCircle(right, top, mScaleDotRadius, mPaint)
        // 左中间控制点，横向缩放
        canvas.drawCircle(left, top + (bottom - top) / 2, mScaleDotRadius, mPaint)
        // 右中间控制点，横向缩放
        canvas.drawCircle(right, top + (bottom - top) / 2, mScaleDotRadius, mPaint)
        // 左下角控制点，等比缩放
        canvas.drawCircle(left, bottom, mScaleDotRadius, mPaint)
        // 右下角控制点，等比缩放
        canvas.drawCircle(right, bottom, mScaleDotRadius, mPaint)
        // 下中间控制点，竖向缩放
        val middleX = (right - left) / 2 + left
        canvas.drawCircle(middleX, bottom, mScaleDotRadius, mPaint)
        // 上中间控制点，旋转
        val rotateLine = mRotateDotRadius / 3
        canvas.drawLine(middleX, top - rotateLine, middleX, top, mPaint)
        canvas.drawCircle(middleX, top - rotateLine - mRotateDotRadius, mRotateDotRadius, mPaint)
        // 上中间控制点，旋转图标
        canvas.drawBitmap(
            mRotateIcon,
            middleX - mRotateIcon.width / 2,
            top - rotateLine - mRotateDotRadius - mRotateIcon.width / 2,
            mPaint
        )
    }

    //@SuppressLint("ClickableViewAccessibility")
    fun onTouchEvent(event: MotionEvent): Boolean {

        // x坐标
        val x = event.x
        // y坐标
        val y = event.y
        // 图片显示区域
        val imageRect = getImageRectF()
        // 图片中心点x坐标
        val centerX = (imageRect.right - imageRect.left) / 2 + imageRect.left
        // 图片中心点y坐标
        val centerY = (imageRect.bottom - imageRect.top) / 2 + imageRect.top

        when (event.action.and(ACTION_MASK)) {
            ACTION_DOWN -> {
                // 按下监听
                mDownClickListener?.invoke(view, PointF(x, y))
                // 判断是否在图片实际显示区域内
                touchMode = getTouchMode(view, x, y)
                if (touchMode == TouchMode.TOUCH_OUTSIDE) {
                    mShowFrame = false
                    invalidate()
                    return false
                }
                mDownX = x
                mDownY = y
                mLastX = x
                mLastY = y
                // 旋转控制点，点击后以图片中心为基准，计算当前旋转角度
                if (touchMode == TouchMode.TOUCH_ROTATE) {
                    // 旋转角度
                    mDegree = callRotation(centerX, centerY, x, y)
                }
                mShowFrame = true
                invalidate()

                // 长按监听计时
                mLongClickJob = coroutineDelay(Dispatchers.Main, 500) {
                    val offsetX = abs(x - mLastX)
                    val offsetY = abs(y - mLastY)
                    val offset = dp2px(context, 10f)
                    if (offsetX <= offset && offsetY <= offset) {
                        mLongClickListener?.invoke(view, PointF(x, y))
                    }
                }
                return true
            }
            ACTION_CANCEL -> {
                mLongClickJob?.cancel()
            }
            ACTION_POINTER_DOWN -> {
                mLongClickJob?.cancel()
                mDegree = callRotation(event)
                mIsPointerDown = true
                return true
            }
            ACTION_MOVE -> {
                // 旋转事件
                if (event.pointerCount == 2) {
                    if (!mIsPointerDown) {
                        return true
                    }
                    val rotate = callRotation(event)
                    val rotateNow = rotate - mDegree
                    mDegree = rotate
                    mImgMatrix.postRotate(rotateNow, centerX, centerY)
                    return true
                }
                if (mIsPointerDown) {
                    return true
                }
                // 移动、缩放事件
                touchMove(x, y, imageRect)
                mLastX = x
                mLastY = y
                invalidate()
                val offsetX = abs(x - mDownX)
                val offsetY = abs(y - mDownY)
                val offset = dp2px(context, 10f)
                if (offsetX > offset || offsetY > offset) {
                    mMoveListener?.invoke(view, PointF(x, y))
                }
                return true
            }
            ACTION_UP -> {
                mLongClickJob?.cancel()
                touchMode = null
                mIsPointerDown = false
                mDegree = 0f
            }
        }
        return false
    }

    private fun invalidate() {
       view.invalidate()
    }

    private fun getImageRectF(): RectF {
        // 获得ImageView中Image的变换矩阵
        val matrix = if(view is ImageView) view.imageMatrix else matrixGet?.invoke()?:throw IllegalArgumentException("matrix must get")
        return getImageRectF(view, matrix)
    }

    /**
     * 手指移动
     *
     * @param x         x坐标
     * @param y         y坐标
     * @param imageRect 图片显示区域
     */
    private fun touchMove(x: Float, y: Float, imageRect: RectF) {
        // 左上角x坐标
        val left = imageRect.left
        // 左上角y坐标
        val top = imageRect.top
        // 右下角x坐标
        val right = imageRect.right
        // 右下角y坐标
        val bottom = imageRect.bottom
        // 总的缩放距离，斜角
        val totalTransOblique = getDistanceOf2Points(left, top, right, bottom)
        // 总的缩放距离，水平
        val totalTransHorizontal = getDistanceOf2Points(left, top, right, top)
        // 总的缩放距离，垂直
        val totalTransVertical = getDistanceOf2Points(left, top, left, bottom)
        // 当前缩放距离
        val scaleTrans = getDistanceOf2Points(mLastX, mLastY, x, y)
        // 缩放系数，x轴方向
        val scaleFactorX: Float
        // 缩放系数，y轴方向
        val scaleFactorY: Float
        // 缩放基准点x坐标
        val scaleBaseX: Float
        // 缩放基准点y坐标
        val scaleBaseY: Float

        when (touchMode) {
            TouchMode.TOUCH_IMAGE -> {
                mImgMatrix.postTranslate(x - mLastX, y - mLastY)
                return
            }
            TouchMode.TOUCH_ROTATE -> {
                // 图片中心点x坐标
                val centerX = (imageRect.right - imageRect.left) / 2 + imageRect.left
                // 图片中心点y坐标
                val centerY = (imageRect.bottom - imageRect.top) / 2 + imageRect.top
                // 旋转角度
                val rotate = callRotation(centerX, centerY, x, y)
                val rotateNow = rotate - mDegree
                mDegree = rotate
                mImgMatrix.postRotate(rotateNow, centerX, centerY)
                return
            }
            TouchMode.TOUCH_CONTROL_1 -> {
                // 缩小
                scaleFactorX = if (x - mLastX > 0) {
                    (totalTransOblique - scaleTrans) / totalTransOblique
                } else {
                    (totalTransOblique + scaleTrans) / totalTransOblique
                }
                scaleFactorY = scaleFactorX
                // 右下角
                scaleBaseX = imageRect.right
                scaleBaseY = imageRect.bottom
            }
            TouchMode.TOUCH_CONTROL_2 -> {
                // 缩小
                scaleFactorX = if (x - mLastX < 0) {
                    (totalTransOblique - scaleTrans) / totalTransOblique
                } else {
                    (totalTransOblique + scaleTrans) / totalTransOblique
                }
                scaleFactorY = scaleFactorX
                // 左下角
                scaleBaseX = imageRect.left
                scaleBaseY = imageRect.bottom
            }
            TouchMode.TOUCH_CONTROL_3 -> {
                // 缩小
                scaleFactorX = if (x - mLastX > 0) {
                    (totalTransOblique - scaleTrans) / totalTransOblique
                } else {
                    (totalTransOblique + scaleTrans) / totalTransOblique
                }
                scaleFactorY = scaleFactorX
                // 右上角
                scaleBaseX = imageRect.right
                scaleBaseY = imageRect.top
            }
            TouchMode.TOUCH_CONTROL_4 -> {
                // 缩小
                scaleFactorX = if (x - mLastX < 0) {
                    (totalTransOblique - scaleTrans) / totalTransOblique
                } else {
                    (totalTransOblique + scaleTrans) / totalTransOblique
                }
                scaleFactorY = scaleFactorX
                // 左上角
                scaleBaseX = imageRect.left
                scaleBaseY = imageRect.top
            }
            TouchMode.TOUCH_CONTROL_5 -> {
                // 缩小
                scaleFactorX = if (x - mLastX > 0) {
                    (totalTransHorizontal - scaleTrans) / totalTransHorizontal
                } else {
                    (totalTransHorizontal + scaleTrans) / totalTransHorizontal
                }
                scaleFactorY = 1f
                // 右上角
                scaleBaseX = imageRect.right
                scaleBaseY = imageRect.top
            }
            TouchMode.TOUCH_CONTROL_6 -> {
                // 缩小
                scaleFactorX = if (x - mLastX < 0) {
                    (totalTransHorizontal - scaleTrans) / totalTransHorizontal
                } else {
                    (totalTransHorizontal + scaleTrans) / totalTransHorizontal
                }
                scaleFactorY = 1f
                // 左上角
                scaleBaseX = imageRect.left
                scaleBaseY = imageRect.top
            }
            TouchMode.TOUCH_CONTROL_7 -> {
                // 缩小
                scaleFactorX = 1f
                scaleFactorY = if (y - mLastY < 0) {
                    (totalTransVertical - scaleTrans) / totalTransVertical
                } else {
                    (totalTransVertical + scaleTrans) / totalTransVertical
                }
                // 左上角
                scaleBaseX = imageRect.left
                scaleBaseY = imageRect.top
            }
            else -> {
                return
            }
        }

        // 最小缩放值限制
        val scaleMatrix = Matrix(mImgMatrix)
        scaleMatrix.postScale(scaleFactorX, scaleFactorY, scaleBaseX, scaleBaseY)
        val scaleRectF = getImageRectF(view, scaleMatrix)
        if (scaleRectF.right - scaleRectF.left < mScaleDotRadius * 6
            || scaleRectF.bottom - scaleRectF.top < mScaleDotRadius * 6
        ) {
            return
        }
        // 缩放
        mImgMatrix.postScale(scaleFactorX, scaleFactorY, scaleBaseX, scaleBaseY)
    }

    /**
     * 隐藏控制框
     */
    fun hideControlFrame() {
        mShowFrame = false
        invalidate()
    }

    /**
     * 设置按下监听
     *
     * @param listener 监听回调
     */
    fun setOnImageDownClickListener(listener: (view: View, pointF: PointF) -> Unit) {
        this.mDownClickListener = listener
    }

    /**
     * 设置长按监听
     *
     * @param listener 监听回调
     */
    fun setOnImageLongClickListener(listener: (view: View, pointF: PointF) -> Unit) {
        this.mLongClickListener = listener
    }

    /**
     * 设置移动监听
     *
     * @param listener 监听回调
     */
    fun setOnImageMoveListener(listener: (view: View, pointF: PointF) -> Unit) {
        this.mMoveListener = listener
    }

    /**
     * dp转px
     *
     * @param context 上下文
     * @param dp      dp单位值
     * @return px单位制
     */
    private fun dp2px(context: Context, dp: Float): Float {
        return TypedValue.applyDimension(COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics)
    }


    /**
     * 是否点击了图片的实际显示区域
     *
     * @param view ImageView
     * @param x    点击x坐标
     * @param y    点击y坐标
     * @return true: 区域内 false: 区域外
     */
    internal fun getTouchMode(view: View, x: Float, y: Float): TouchMode {
        val imageRect = getImageRectF()
        val left = imageRect.left
        val top = imageRect.top
        val right = imageRect.right
        val bottom = imageRect.bottom
        // 扩大点击区域
        val offset = mScaleDotRadius * 3

        val rect1 = RectF(left - offset, top - offset, left + offset, top + offset)
        if (rect1.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_1
        }
        val rect2 = RectF(right - offset, top - offset, right + offset, top + offset)
        if (rect2.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_2
        }
        val rect3 = RectF(left - offset, bottom - offset, left + offset, bottom + offset)
        if (rect3.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_3
        }
        val rect4 = RectF(right - offset, bottom - offset, right + offset, bottom + offset)
        if (rect4.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_4
        }
        val rect5Y = (bottom - top) / 2 + top
        val rect5 = RectF(left - offset, rect5Y - offset, left + offset, rect5Y + offset)
        if (rect5.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_5
        }
        val rect6Y = (bottom - top) / 2 + top
        val rect6 = RectF(right - offset, rect6Y - offset, right + offset, rect6Y + offset)
        if (rect6.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_6
        }
        val rect7X = (right - left) / 2 + left
        val rect7 = RectF(rect7X - offset, bottom - offset, rect7X + offset, bottom + offset)
        if (rect7.contains(x, y)) {
            return TouchMode.TOUCH_CONTROL_7
        }
        // 旋转控制点半径
        val rotateDotRadius = mRotateDotRadius
        // 旋转控制点的中心x坐标
        val rectRotateX = (right - left) / 2 + left
        // rotateDotRadius / 3 是连接线的长度
        val rectRotate = RectF(
            rectRotateX - rotateDotRadius,
            top - rotateDotRadius / 3 - rotateDotRadius * 2,
            rectRotateX + rotateDotRadius,
            top - rotateDotRadius / 3,
        )
        if (rectRotate.contains(x, y)) {
            return TouchMode.TOUCH_ROTATE
        }
        if (imageRect.contains(x, y)) {
            return TouchMode.TOUCH_IMAGE
        }
        return TouchMode.TOUCH_OUTSIDE
    }


    /**
     * 获取图片在ImageView中的实际显示位置
     *
     * @param view ImageView
     * @param matrix Matrix
     * @return RectF
     */
    private fun getImageRectF(view: View, matrix: Matrix): RectF {
        // 获得ImageView中Image的显示边界
        val bounds =
            if(view is ImageView)
               view.drawable.bounds
            else
                view.clipBounds
        val rectF = RectF()
        matrix.mapRect(
            rectF,
            RectF(
                bounds.left.toFloat(),
                bounds.top.toFloat(),
                bounds.right.toFloat(),
                bounds.bottom.toFloat()
            )
        )
        return rectF
    }



    /**
     * 获取两个点之间的距离
     *
     * @param x1 第一个点x坐标
     * @param y1 第一个点y坐标
     * @param x2 第二个点x坐标
     * @param y2 第二个点y坐标
     * @return 两个点之间的距离
     */
    private fun getDistanceOf2Points(x1: Float, y1: Float, x2: Float, y2: Float): Float {
        return sqrt((x1 - x2).pow(2f) + (y1 - y2).pow(2f)).toFloat()
    }

    /**
     * 计算旋转的角度
     *
     * @param event MotionEvent
     * @return 旋转的角度
     */
    internal fun callRotation(event: MotionEvent): Float {
        val deltaX = (event.getX(0) - event.getX(1)).toDouble()
        val deltaY = (event.getY(0) - event.getY(1)).toDouble()
        val radius = atan2(deltaY, deltaX)
        return Math.toDegrees(radius).toFloat()
    }

    /**
     * 计算旋转的角度
     *
     * @param baseX 基准点x坐标
     * @param baseY 基准点y坐标
     * @param rotateX 旋转点x坐标
     * @param rotateY 旋转点y坐标
     * @return 旋转的角度
     */
    internal fun callRotation(baseX: Float, baseY: Float, rotateX: Float, rotateY: Float): Float {
        val deltaX = (baseX - rotateX).toDouble()
        val deltaY = (baseY - rotateY).toDouble()
        val radius = atan2(deltaY, deltaX)
        return Math.toDegrees(radius).toFloat()
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouch(v: View?, event: MotionEvent): Boolean {
        return onTouchEvent(event)
    }

}

/**
 * 点击模式
 */
internal enum class TouchMode {
    /**
     * 区域外
     */
    TOUCH_OUTSIDE,

    /**
     * 图片显示区域
     */
    TOUCH_IMAGE,

    /**
     * 旋转控制点
     */
    TOUCH_ROTATE,

    /**
     * 左上角控制点，等比缩放
     */
    TOUCH_CONTROL_1,

    /**
     * 右上角控制点，等比缩放
     */
    TOUCH_CONTROL_2,

    /**
     * 左下角控制点，等比缩放
     */
    TOUCH_CONTROL_3,

    /**
     * 右下角控制点，等比缩放
     */
    TOUCH_CONTROL_4,

    /**
     * 左中间控制点，横向缩放
     */
    TOUCH_CONTROL_5,

    /**
     * 右中间控制点，横向缩放
     */
    TOUCH_CONTROL_6,

    /**
     * 下中间控制点，竖向缩放
     */
    TOUCH_CONTROL_7,
}